package implementation;

import entities.Genre;
import entities.Medium;
import entities.MediumType;
import entities.Movie;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import managers.IOManager;
import managers.MediumManager;
import managers.MovieManager;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.odftoolkit.simple.SpreadsheetDocument;
import org.odftoolkit.simple.table.Row;
import org.odftoolkit.simple.table.Table;
import utilities.InvalidFormatException;

/**
 *
 * @author Hacnar
 */
public class IOManagerImpl implements IOManager {

    private static final String[] MOVIELABELS = new String[]{"Title","Note","Runtime","Cast","Directors","Release Year","Genres","Countries of Origin"};
    private static final String[] MEDIUMLABELS = new String[]{"Title","Type","Lended","Note","Movies"};
    
    @Override
    public void exportToODF(String fileName) {
        SpreadsheetDocument doc = null;
        try {
            doc = SpreadsheetDocument.newSpreadsheetDocument();
        } catch (Exception ex) {
            Logger.getLogger(IOManagerImpl.class.getName()).log(Level.WARN, "Could not create odf document", ex);
        }
        MediumManager mediumManager = new MediumManagerImpl();
        MovieManager movieManager = new MovieManagerImpl();
        List<Medium> media = mediumManager.getAllMedia();
        Table mediaTable = doc.getSheetByIndex(0);
        mediaTable.setTableName("Media"); 
        Row header = mediaTable.getRowByIndex(0);
        for (int i = 0; i < 5; i++) {
            header.getCellByIndex(i).setStringValue(MEDIUMLABELS[i]);
        }
        for (int i = 0; i < media.size(); i++) {
            Medium medium = media.get(i);
            Row nextRow = mediaTable.getRowByIndex(i+1);
            nextRow.getCellByIndex(0).setStringValue(medium.getTitle());
            nextRow.getCellByIndex(1).setStringValue(medium.getType().toString());
            nextRow.getCellByIndex(2).setStringValue(medium.isLended() ? "yes" : "no");
            nextRow.getCellByIndex(3).setStringValue(medium.getNote());
            String str = "";
            for (String s : medium.getMovies()) {
                str = str+movieManager.getMovieByID(s).getTitle()+"; ";
            }
            if (!str.isEmpty()) nextRow.getCellByIndex(4).setStringValue(str.substring(0, str.length()-2));
        }
        
        
        List<Movie> movies = movieManager.getAllMovies();
        Table moviesTable = doc.appendSheet("Movies");
        header = moviesTable.getRowByIndex(0);
        for (int i = 0; i < 8; i++) {
            header.getCellByIndex(i).setStringValue(MOVIELABELS[i]);
        }
        for (int i = 0; i < movies.size(); i++) {
            Movie movie = movies.get(i);
            Row nextRow = moviesTable.getRowByIndex(i+1);
            
            nextRow.getCellByIndex(0).setStringValue(movie.getTitle());
            nextRow.getCellByIndex(1).setStringValue(movie.getNote());
            nextRow.getCellByIndex(2).setStringValue(String.valueOf(movie.getRunTime()));
            String str = movie.getCast().toString();
            nextRow.getCellByIndex(3).setStringValue(str.substring(1, str.length()-1));
            str = movie.getDirectors().toString();
            nextRow.getCellByIndex(4).setStringValue(str.substring(1, str.length()-1));
            nextRow.getCellByIndex(5).setStringValue(String.valueOf(movie.getReleaseYear()));
            str = movie.getGenres().toString();
            nextRow.getCellByIndex(6).setStringValue(str.substring(1, str.length()-1));
            str = movie.getCountriesOfOrigin().toString();
            nextRow.getCellByIndex(7).setStringValue(str.substring(1, str.length()-1));
        }
        moviesTable.setTableName("Movies");
        File file = null;
        if (fileName.substring(fileName.length()-4).equals(".ods")) file = new File(fileName);
        else file = new File(fileName+".ods");
        try {
            doc.save(file);
        } catch (Exception ex) {
            Logger.getLogger(IOManagerImpl.class.getName()).log(Level.WARN, "Could not save odf document", ex);
        }
        doc.close();
    }

    @Override
    public void importFromODF(String fileName) throws InvalidFormatException {
        
        MediumManager mediumManager = new MediumManagerImpl();
        MovieManager movieManager = new MovieManagerImpl();
        SpreadsheetDocument doc = null;
        try {
            doc = SpreadsheetDocument.loadDocument(fileName);
        } catch (Exception ex) {
            Logger.getLogger(IOManagerImpl.class.getName()).log(Level.WARN, null, ex);
        }
        if (doc == null) {
            throw new InvalidFormatException("Media type not supported");
        }
        if (doc.getSheetCount() != 2) {
            throw new InvalidFormatException("Wrong number of sheets");
        }
        Table mediaTable = doc.getSheetByName("Media");
        Table moviesTable = doc.getSheetByName("Movies");
        if (mediaTable == null || moviesTable == null) {
            throw new InvalidFormatException("Sheets names mismatch");
        }
        Row header = mediaTable.getRowByIndex(0);
        for (int i = 0; i < 5; i++) {
            if (!header.getCellByIndex(i).getStringValue().equals(MEDIUMLABELS[i])) {
                throw new InvalidFormatException("Wrong header row format");
            }
        }
        header = moviesTable.getRowByIndex(0);
        for (int i = 0; i < 8; i++) {
            if (!header.getCellByIndex(i).getStringValue().equals(MOVIELABELS[i])) {
                throw new InvalidFormatException("Wrong header row format");
            }
        }
        
        List<Movie> loadedMovies = new ArrayList<Movie>();
        for (int i = 1; i < moviesTable.getRowCount(); i++) {
            Movie movie = new Movie();
            Row row = moviesTable.getRowByIndex(i);
            movie.setTitle(row.getCellByIndex(0).getStringValue());
            movie.setNote(row.getCellByIndex(1).getStringValue());
            try {
                movie.setRunTime(Integer.parseInt(row.getCellByIndex(2).getStringValue()));
            } catch (NumberFormatException ex) {
                Logger.getLogger(IOManagerImpl.class.getName()).log(Level.WARN, "Invalid data in document", ex);
                continue;
            }
            String[] stringData = row.getCellByIndex(3).getStringValue().split(",");
            List<String> strings = new ArrayList<String>(Arrays.asList(stringData));
            for (String s : strings) {
                s.trim();
            }
            movie.setCast(strings);
            stringData = row.getCellByIndex(4).getStringValue().split(",");
            strings = new ArrayList<String>(Arrays.asList(stringData));
            for (String s : strings) {
                s.trim();
            }
            movie.setDirectors(strings);
            try {
                movie.setReleaseYear(Integer.parseInt(row.getCellByIndex(5).getStringValue()));
            } catch (NumberFormatException ex) {
                Logger.getLogger(IOManagerImpl.class.getName()).log(Level.WARN, "Invalid data in document", ex);
                continue;
            }
            stringData = row.getCellByIndex(6).getStringValue().split(",");
            List<Genre> genres = new ArrayList<Genre>();
            for (String s : stringData) {
                s = s.trim();
                genres.add(Genre.valueOf(s));
            }
            movie.setGenres(genres);
            stringData = row.getCellByIndex(7).getStringValue().split(",");
            strings = new ArrayList<String>(Arrays.asList(stringData));
            for (String s : strings) {
                s = s.trim();
            }
            movie.setCountriesOfOrigin(strings);
            movie = movieManager.createMovie(movie);
            loadedMovies.add(movie);
        }
        
        for (int i = 1; i < mediaTable.getRowCount(); i++) {
            Medium medium = new Medium();
            Row row = mediaTable.getRowByIndex(i);
            medium.setTitle(row.getCellByIndex(0).getStringValue());
            medium.setType(MediumType.valueOf(row.getCellByIndex(1).getStringValue()));
            medium.setLended(row.getCellByIndex(2).getStringValue().equals("yes"));
            medium.setNote(row.getCellByIndex(3).getStringValue());
            String[] stringData = row.getCellByIndex(4).getStringValue().split(";");
            List<String> movieIds = new ArrayList<String>();
            for (String s : stringData) {
                s = s.trim();
                for (Movie m : loadedMovies) {
                    if (s.equals(m.getTitle())) movieIds.add(m.getId());
                }
            }
            medium.setMovies(movieIds);
            mediumManager.createMedium(medium);
            
        }
    }
    
}
